GdkWindow *window,
gboolean add_filter)
{
- gint old_warnings = 0; /* quiet gcc */
-
gdk_error_trap_push ();
if (!GDK_WINDOW_DESTROYED (window))
static GtkWidget *gtk_drag_get_ipc_widget (void);
static void gtk_drag_release_ipc_widget (GtkWidget *widget);
-static void gtk_drag_highlight_paint (GtkWidget *widget);
static gboolean gtk_drag_highlight_expose (GtkWidget *widget,
GdkEventExpose *event,
gpointer data);
-
-static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
- GtkDragDestSite *site,
- GdkDragContext *context);
-static void gtk_drag_selection_received (GtkWidget *widget,
- GtkSelectionData *selection_data,
- guint32 time,
- gpointer data);
-static void gtk_drag_find_widget (GtkWidget *widget,
- GtkDragFindData *data);
-static void gtk_drag_proxy_begin (GtkWidget *widget,
- GtkDragDestInfo *dest_info);
-static void gtk_drag_dest_info_destroy (gpointer data);
-static void gtk_drag_dest_realized (GtkWidget *widget);
-static void gtk_drag_dest_site_destroy (gpointer data);
-static void gtk_drag_dest_leave (GtkWidget *widget,
- GdkDragContext *context,
- guint time);
-static gboolean gtk_drag_dest_motion (GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
-static gboolean gtk_drag_dest_drop (GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
+static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
+ GtkDragDestSite *site,
+ GdkDragContext *context);
+static void gtk_drag_selection_received (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint32 time,
+ gpointer data);
+static void gtk_drag_find_widget (GtkWidget *widget,
+ GtkDragFindData *data);
+static void gtk_drag_proxy_begin (GtkWidget *widget,
+ GtkDragDestInfo *dest_info,
+ guint32 time);
+static void gtk_drag_dest_realized (GtkWidget *widget);
+static void gtk_drag_dest_site_destroy (gpointer data);
+static void gtk_drag_dest_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time);
+static gboolean gtk_drag_dest_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time);
+static gboolean gtk_drag_dest_drop (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time);
+
+static GtkDragDestInfo * gtk_drag_get_dest_info (GdkDragContext *context,
+ gboolean create);
+static GtkDragSourceInfo *gtk_drag_get_source_info (GdkDragContext *context,
+ gboolean create);
+static void gtk_drag_clear_source_info (GdkDragContext *context);
static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
GdkAtom selection,
gpointer data);
static gint gtk_drag_anim_timeout (gpointer data);
static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
-static void gtk_drag_source_info_destroy (gpointer data);
+static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info);
static void gtk_drag_update (GtkDragSourceInfo *info,
gint x_root,
gint y_root,
}
/*************************************************************
- * gtk_drag_highlight_paint:
- * Paint a highlight indicating drag status onto the widget.
+ * gtk_drag_highlight_expose:
+ * Callback for expose_event for highlighted widgets.
* arguments:
* widget:
+ * event:
+ * data:
* results:
*************************************************************/
-static void
-gtk_drag_highlight_paint (GtkWidget *widget)
+static gboolean
+gtk_drag_highlight_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
{
gint x, y, width, height;
-
- g_return_if_fail (widget != NULL);
-
+
if (GTK_WIDGET_DRAWABLE (widget))
{
if (GTK_WIDGET_NO_WINDOW (widget))
FALSE,
x, y, width - 1, height - 1);
}
-}
-/*************************************************************
- * gtk_drag_highlight_expose:
- * Callback for expose_event for highlighted widgets.
- * arguments:
- * widget:
- * event:
- * data:
- * results:
- *************************************************************/
-
-static gboolean
-gtk_drag_highlight_expose (GtkWidget *widget,
- GdkEventExpose *event,
- gpointer data)
-{
- gtk_drag_highlight_paint (widget);
return TRUE;
}
{
g_return_if_fail (widget != NULL);
- gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
- GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
- NULL);
gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
NULL);
context = event->dnd.context;
- info = g_dataset_get_data (context, "gtk-info");
- if (!info)
- {
- info = g_new (GtkDragDestInfo, 1);
- info->widget = NULL;
- info->context = event->dnd.context;
- info->proxy_source = NULL;
- info->proxy_data = NULL;
- info->dropped = FALSE;
- info->proxy_drop_wait = FALSE;
- g_object_set_qdata_full (G_OBJECT (context),
- g_quark_from_static_string ("gtk-info"),
- info,
- gtk_drag_dest_info_destroy);
- }
+ info = gtk_drag_get_dest_info (context, TRUE);
/* Find the widget for the event */
switch (event->type)
drop_widget = data;
context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
- info = g_object_get_qdata (G_OBJECT (context), g_quark_from_static_string ("gtk-info"));
+ info = gtk_drag_get_dest_info (context, FALSE);
if (info->proxy_data &&
info->proxy_data->target == selection_data->target)
static void
gtk_drag_proxy_begin (GtkWidget *widget,
- GtkDragDestInfo *dest_info)
+ GtkDragDestInfo *dest_info,
+ guint32 time)
{
GtkDragSourceInfo *source_info;
GList *tmp_list;
+ GdkDragContext *context;
+ GtkWidget *ipc_widget;
+
+ if (dest_info->proxy_source)
+ {
+ gdk_drag_abort (dest_info->proxy_source->context, time);
+ gtk_drag_source_info_destroy (dest_info->proxy_source);
+ dest_info->proxy_source = NULL;
+ }
- source_info = g_new0 (GtkDragSourceInfo, 1);
- source_info->ipc_widget = gtk_drag_get_ipc_widget ();
-
- source_info->widget = widget;
- gtk_widget_ref (source_info->widget);
- source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
- dest_info->context->targets);
+ ipc_widget = gtk_drag_get_ipc_widget ();
+ context = gdk_drag_begin (ipc_widget->window,
+ dest_info->context->targets);
+
+ source_info = gtk_drag_get_source_info (context, TRUE);
+
+ source_info->ipc_widget = ipc_widget;
+ source_info->widget = gtk_widget_ref (widget);
source_info->target_list = gtk_target_list_new (NULL, 0);
tmp_list = dest_info->context->targets;
source_info->proxy_dest = dest_info;
- g_object_set_qdata (G_OBJECT (source_info->context),
- g_quark_from_static_string ("gtk-info"),
- source_info);
-
- gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
+ gtk_signal_connect (GTK_OBJECT (ipc_widget),
"selection_get",
GTK_SIGNAL_FUNC (gtk_drag_selection_get),
source_info);
g_free (info);
}
+static GtkDragDestInfo *
+gtk_drag_get_dest_info (GdkDragContext *context,
+ gboolean create)
+{
+ GtkDragDestInfo *info;
+ static GQuark info_quark = 0;
+ if (!info_quark)
+ info_quark = g_quark_from_static_string ("gtk-dest-info");
+
+ info = g_object_get_qdata (G_OBJECT (context), info_quark);
+ if (!info && create)
+ {
+ info = g_new (GtkDragDestInfo, 1);
+ info->widget = NULL;
+ info->context = context;
+ info->proxy_source = NULL;
+ info->proxy_data = NULL;
+ info->dropped = FALSE;
+ info->proxy_drop_wait = FALSE;
+ g_object_set_qdata_full (G_OBJECT (context), info_quark,
+ info, gtk_drag_dest_info_destroy);
+ }
+
+ return info;
+}
+
+static GQuark dest_info_quark = 0;
+
+static GtkDragSourceInfo *
+gtk_drag_get_source_info (GdkDragContext *context,
+ gboolean create)
+{
+ GtkDragSourceInfo *info;
+ if (!dest_info_quark)
+ dest_info_quark = g_quark_from_static_string ("gtk-source-info");
+
+ info = g_object_get_qdata (G_OBJECT (context), dest_info_quark);
+ if (!info && create)
+ {
+ info = g_new0 (GtkDragSourceInfo, 1);
+ info->context = context;
+ g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
+ }
+
+ return info;
+}
+
+static void
+gtk_drag_clear_source_info (GdkDragContext *context)
+{
+ g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
+}
+
static void
gtk_drag_dest_realized (GtkWidget *widget)
{
if (site->do_proxy)
{
- GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
- g_quark_from_static_string ("gtk-info"));
+ GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
- if (info->proxy_source && !info->dropped)
- gdk_drag_abort (info->proxy_source->context, time);
+ if (info->proxy_source && info->proxy_source->widget == widget && !info->dropped)
+ {
+ gdk_drag_abort (info->proxy_source->context, time);
+ gtk_drag_source_info_destroy (info->proxy_source);
+ info->proxy_source = NULL;
+ }
return;
}
GdkWindow *dest_window;
GdkDragProtocol proto;
- GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
- g_quark_from_static_string ("gtk-info"));
+ GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
- if (!info->proxy_source)
- gtk_drag_proxy_begin (widget, info);
+ if (!info->proxy_source || info->proxy_source->widget != widget)
+ gtk_drag_proxy_begin (widget, info, time);
current_event = gtk_get_current_event ();
site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
g_return_val_if_fail (site != NULL, FALSE);
- info = g_object_get_qdata (G_OBJECT (context),
- g_quark_from_static_string ("gtk-info"));
+ info = gtk_drag_get_dest_info (context, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
info->drop_x = x;
GdkWindow *dest_window;
GdkDragProtocol proto;
- gtk_drag_proxy_begin (widget, info);
+ gtk_drag_proxy_begin (widget, info, time);
info->proxy_drop_wait = TRUE;
info->proxy_drop_time = time;
gtk_drag_source_check_selection (info->proxy_source, selection, time);
gdk_event_free (current_event);
-
}
return TRUE;
GList *tmp_list;
guint32 time = GDK_CURRENT_TIME;
GdkDragAction possible_actions, suggested_action;
+ GdkDragContext *context;
+ GtkWidget *ipc_widget;
g_return_val_if_fail (widget != NULL, NULL);
g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
if (event)
time = gdk_event_get_time (event);
- info = g_new0 (GtkDragSourceInfo, 1);
- info->ipc_widget = gtk_drag_get_ipc_widget ();
- source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
-
- gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
-
tmp_list = g_list_last (target_list->list);
while (tmp_list)
{
tmp_list = tmp_list->prev;
}
- info->widget = widget;
- gtk_widget_ref (info->widget);
-
- info->context = gdk_drag_begin (info->ipc_widget->window, targets);
+ ipc_widget = gtk_drag_get_ipc_widget ();
+ source_widgets = g_slist_prepend (source_widgets, ipc_widget);
+
+ context = gdk_drag_begin (ipc_widget->window, targets);
g_list_free (targets);
- g_object_set_qdata (G_OBJECT (info->context),
- g_quark_from_static_string ("gtk-info"), info);
+ info = gtk_drag_get_source_info (context, TRUE);
+
+ info->ipc_widget = ipc_widget;
+ gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
+
+ info->widget = gtk_widget_ref (widget);
+
info->button = button;
info->target_list = target_list;
gtk_target_list_ref (target_list);
g_return_if_fail (context != NULL);
g_return_if_fail (widget != NULL);
- info = g_object_get_qdata (G_OBJECT (context),
- g_quark_from_static_string ("gtk-info"));
+ info = gtk_drag_get_source_info (context, FALSE);
gtk_drag_remove_icon (info);
info->icon_window = widget;
g_return_if_fail (event != NULL);
context = event->dnd.context;
- info = g_object_get_qdata (G_OBJECT (context),
- g_quark_from_static_string ("gtk-info"));
+ info = gtk_drag_get_source_info (context, FALSE);
if (!info)
return;
/* Mark the context as dead, so if the destination decides
* to respond really late, we still are OK.
*/
- g_object_set_qdata (G_OBJECT (info->context),
- g_quark_from_static_string ("gtk-info"), NULL);
+ gtk_drag_clear_source_info (info->context);
gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
}
}
GDK_BUTTON1_MASK << (i - 1))
break;
}
-
- if (MAX (ABS (site->x - event->motion.x),
- ABS (site->y - event->motion.y)) > 3)
+
+ if (gtk_drag_check_threshold (widget, site->x, site->y,
+ event->motion.x, event->motion.y))
{
GtkDragSourceInfo *info;
GdkDragContext *context;
site->actions,
i, event);
-
- info = g_object_get_qdata (G_OBJECT (context),
- g_quark_from_static_string ("gtk-info"));
-
+ info = gtk_drag_get_source_info (context, FALSE);
if (!info->icon_window)
{
if (site->pixmap)
}
static void
-gtk_drag_source_info_destroy (gpointer data)
+gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
{
- GtkDragSourceInfo *info = data;
-
- gtk_drag_remove_icon (data);
+ gtk_drag_remove_icon (info);
if (!info->proxy_dest)
gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
gtk_target_list_unref (info->target_list);
- g_object_set_qdata (G_OBJECT (info->context), g_quark_from_static_string ("gtk-info"), NULL);
+ gtk_drag_clear_source_info (info->context);
gdk_drag_context_unref (info->context);
if (info->drop_timeout)
return FALSE;
}
+
+/**
+ * gtk_drag_check_threshold:
+ * @widget: a #GtkWidget
+ * @start_x: X coordinate of start of drag
+ * @start_y: Y coordinate of start of drag
+ * @current_x: current X coordinate
+ * @current_y: current Y coordinate
+ *
+ * Checks to see if a mouse drag starting at (start_x, start_y) and ending
+ * at (current_x, current_y) has passed the GTK drag threshhold, and thus
+ * should trigger the beginning of a drag-and-drop operation.
+ *
+ * Return Value: If the drag threshold has been passed.
+ **/
+gboolean
+gtk_drag_check_threshold (GtkWidget *widget,
+ gint start_x,
+ gint start_y,
+ gint current_x,
+ gint current_y)
+{
+#define DRAG_THRESHOLD 8
+
+ return (ABS (current_x - start_x) > DRAG_THRESHOLD ||
+ ABS (current_y - start_y) > DRAG_THRESHOLD);
+}
gint hot_y);
+gboolean gtk_drag_check_threshold (GtkWidget *widget,
+ gint start_x,
+ gint start_y,
+ gint current_x,
+ gint current_y);
+
/* Internal functions */
void gtk_drag_source_handle_event (GtkWidget *widget,
GdkEvent *event);
#include "gdk/gdkkeysyms.h"
#include "gtkbindings.h"
#include "gtkclipboard.h"
+#include "gtkdnd.h"
#include "gtkentry.h"
#include "gtkimmulticontext.h"
#include "gtkintl.h"
static guint signals[LAST_SIGNAL] = { 0 };
+typedef enum {
+ CURSOR_STANDARD,
+ CURSOR_DND
+} CursorType;
+
+static GtkTargetEntry target_table[] = {
+ { "UTF8_STRING", 0, 0 },
+ { "COMPOUND_TEXT", 0, 0 },
+ { "TEXT", 0, 0 },
+ { "text/plain", 0, 0 },
+ { "STRING", 0, 0 }
+};
+
/* GObject, GtkObject methods
*/
static void gtk_entry_class_init (GtkEntryClass *klass);
static void gtk_entry_state_changed (GtkWidget *widget,
GtkStateType previous_state);
+static gboolean gtk_entry_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time);
+static void gtk_entry_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time);
+static void gtk_entry_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time);
+static void gtk_entry_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time);
+static void gtk_entry_drag_data_delete (GtkWidget *widget,
+ GdkDragContext *context);
+
/* GtkEditable method implementations
*/
static void gtk_entry_insert_text (GtkEditable *editable,
/* Internal routines
*/
static void gtk_entry_draw_text (GtkEntry *entry);
-static void gtk_entry_draw_cursor (GtkEntry *entry);
+static void gtk_entry_draw_cursor (GtkEntry *entry,
+ CursorType type);
static PangoLayout *gtk_entry_get_layout (GtkEntry *entry,
gboolean include_preedit);
static void gtk_entry_queue_draw (GtkEntry *entry);
static gint gtk_entry_find_position (GtkEntry *entry,
gint x);
static void gtk_entry_get_cursor_locations (GtkEntry *entry,
+ CursorType type,
gint *strong_x,
gint *weak_x);
static void gtk_entry_adjust_scroll (GtkEntry *entry);
widget_class->direction_changed = gtk_entry_direction_changed;
widget_class->state_changed = gtk_entry_state_changed;
+ widget_class->drag_motion = gtk_entry_drag_motion;
+ widget_class->drag_leave = gtk_entry_drag_leave;
+ widget_class->drag_data_received = gtk_entry_drag_data_received;
+ widget_class->drag_data_get = gtk_entry_drag_data_get;
+ widget_class->drag_data_delete = gtk_entry_drag_data_delete;
+
class->insert_text = gtk_entry_real_insert_text;
class->delete_text = gtk_entry_real_delete_text;
class->move_cursor = gtk_entry_move_cursor;
entry->editable = TRUE;
entry->visible = TRUE;
entry->invisible_char = '*';
+ entry->dnd_position = -1;
+ gtk_drag_dest_set (GTK_WIDGET (entry),
+ GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_HIGHLIGHT,
+ target_table, G_N_ELEMENTS (target_table),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
/* This object is completely private. No external entity can gain a reference
* to it; so we create it here and destroy it in finalize().
*/
else if (entry->text_area == event->window)
{
gtk_entry_draw_text (GTK_ENTRY (widget));
- gtk_entry_draw_cursor (GTK_ENTRY (widget));
+
+ if ((entry->visible || entry->invisible_char != 0) &&
+ GTK_WIDGET_HAS_FOCUS (widget) &&
+ entry->selection_bound == entry->current_pos)
+ gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);
+
+ if (entry->dnd_position != -1)
+ gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
}
return FALSE;
GtkEntry *entry = GTK_ENTRY (widget);
GtkEditable *editable = GTK_EDITABLE (widget);
gint tmp_pos;
+ gint sel_start, sel_end;
entry = GTK_ENTRY (widget);
editable = GTK_EDITABLE (widget);
switch (event->type)
{
case GDK_BUTTON_PRESS:
- gtk_entry_reset_im_context (entry);
-
- entry->current_pos = tmp_pos;
- entry->selection_bound = tmp_pos;
+ if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end) &&
+ tmp_pos >= sel_start && tmp_pos <= sel_end)
+ {
+ /* Click inside the selection - we'll either start a drag, or
+ * clear the selection
+ */
- gtk_entry_recompute (entry);
+ entry->in_drag = TRUE;
+ entry->drag_start_x = event->x + entry->scroll_offset;
+ entry->drag_start_y = event->y + entry->scroll_offset;
+ }
+ else
+ {
+ gtk_entry_reset_im_context (entry);
+
+ entry->current_pos = tmp_pos;
+ entry->selection_bound = tmp_pos;
+
+ gtk_entry_recompute (entry);
+ }
break;
GdkEventButton *event)
{
GtkEntry *entry = GTK_ENTRY (widget);
- GtkEditable *editable = GTK_EDITABLE (widget);
if (event->window != entry->text_area || entry->button != event->button)
return FALSE;
+ if (entry->in_drag)
+ {
+ gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
+
+ gtk_entry_reset_im_context (entry);
+
+ entry->current_pos = tmp_pos;
+ entry->selection_bound = tmp_pos;
+
+ gtk_entry_recompute (entry);
+
+ entry->in_drag = 0;
+ }
+
entry->button = 0;
+ gtk_entry_update_primary_selection (entry);
+
return FALSE;
}
if (event->is_hint || (entry->text_area != event->window))
gdk_window_get_pointer (entry->text_area, NULL, NULL, NULL);
- tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+ if (entry->in_drag)
+ {
+ if (gtk_drag_check_threshold (widget,
+ entry->drag_start_x, entry->drag_start_y,
+ event->x + entry->scroll_offset, event->y))
+ {
+ GdkDragContext *context;
+ GtkTargetList *target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table));
+
+ context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY | GDK_ACTION_MOVE,
+ entry->button, (GdkEvent *)event);
- if (tmp_pos != entry->current_pos)
+
+ entry->in_drag = FALSE;
+ entry->button = 0;
+
+ gtk_target_list_unref (target_list);
+ gtk_drag_set_icon_default (context);
+ }
+ }
+ else
{
- entry->current_pos = tmp_pos;
- gtk_entry_recompute (entry);
+ tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+
+ if (tmp_pos != entry->current_pos)
+ {
+ entry->current_pos = tmp_pos;
+ gtk_entry_recompute (entry);
+ }
}
return TRUE;
}
}
+static char *
+strstr_len (const char *haystack,
+ int haystack_len,
+ const char *needle)
+{
+ int i;
+
+ g_return_val_if_fail (haystack != NULL, NULL);
+ g_return_val_if_fail (needle != NULL, NULL);
+
+ if (haystack_len < 0)
+ return strstr (haystack, needle);
+ else
+ {
+ const char *p = haystack;
+ int needle_len = strlen (needle);
+ const char *end = haystack + haystack_len - needle_len;
+
+ if (needle_len == 0)
+ return (char *)haystack;
+
+ while (*p && p <= end)
+ {
+ for (i = 0; i < needle_len; i++)
+ if (p[i] != needle[i])
+ goto next;
+
+ return (char *)p;
+
+ next:
+ p += needle_len;
+ }
+ }
+
+ return NULL;
+}
+
/* Default signal handlers
*/
static void
{
gint index;
gint n_chars;
+ gchar line_separator[7];
+ gint len;
+ gchar *p;
if (new_text_length < 0)
new_text_length = strlen (new_text);
+ /* We don't want to allow inserting paragraph delimeters
+ */
+ pango_find_paragraph_boundary (new_text, new_text_length, &new_text_length, NULL);
+
+ /* Or line separators - this is really painful
+ */
+ len = g_unichar_to_utf8 (0x2028, line_separator); /* 0x2028 == LS */
+ line_separator[len] = '\0';
+
+ p = strstr_len (new_text, new_text_length, line_separator);
+ if (p)
+ new_text_length = p - new_text;
+
n_chars = g_utf8_strlen (new_text, new_text_length);
if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
{
}
static void
-gtk_entry_draw_cursor (GtkEntry *entry)
+gtk_entry_draw_cursor (GtkEntry *entry,
+ CursorType type)
{
g_return_if_fail (entry != NULL);
g_return_if_fail (GTK_IS_ENTRY (entry));
- if (!entry->visible && entry->invisible_char == 0)
- return;
-
if (GTK_WIDGET_DRAWABLE (entry))
{
GtkWidget *widget = GTK_WIDGET (entry);
- if (GTK_WIDGET_HAS_FOCUS (widget) &&
- (entry->selection_bound == entry->current_pos))
- {
- gint xoffset = INNER_BORDER - entry->scroll_offset;
- gint strong_x, weak_x;
- gint text_area_height;
-
- gdk_window_get_size (entry->text_area, NULL, &text_area_height);
+ gint xoffset = INNER_BORDER - entry->scroll_offset;
+ gint strong_x, weak_x;
+ gint text_area_height;
- gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
-
- gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED],
- xoffset + strong_x, INNER_BORDER,
- xoffset + strong_x, text_area_height - INNER_BORDER);
-
- if (weak_x != strong_x)
- gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL],
- xoffset + weak_x, INNER_BORDER,
- xoffset + weak_x, text_area_height - INNER_BORDER);
-
- }
+ gdk_window_get_size (entry->text_area, NULL, &text_area_height);
+
+ gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
+
+ gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED],
+ xoffset + strong_x, INNER_BORDER,
+ xoffset + strong_x, text_area_height - INNER_BORDER);
+
+ if (weak_x != strong_x)
+ gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL],
+ xoffset + weak_x, INNER_BORDER,
+ xoffset + weak_x, text_area_height - INNER_BORDER);
}
}
}
static void
-gtk_entry_get_cursor_locations (GtkEntry *entry,
- gint *strong_x,
- gint *weak_x)
+gtk_entry_get_cursor_locations (GtkEntry *entry,
+ CursorType type,
+ gint *strong_x,
+ gint *weak_x)
{
PangoLayout *layout = gtk_entry_get_layout (entry, TRUE);
const gchar *text;
PangoRectangle strong_pos, weak_pos;
gint index;
- text = pango_layout_get_text (layout);
-
- index =
- g_utf8_offset_to_pointer (text,
- entry->current_pos +
- entry->preedit_cursor) - text;
-
+ if (type == CURSOR_STANDARD)
+ {
+ text = pango_layout_get_text (layout);
+ index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
+ }
+ else /* type == CURSOR_DND */
+ {
+ index = g_utf8_offset_to_pointer (entry->text, entry->dnd_position) - entry->text;
+ if (entry->dnd_position > entry->current_pos)
+ index += entry->preedit_length;
+ }
+
pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
g_object_unref (G_OBJECT (layout));
* put the weak cursor on screen if possible.
*/
- gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
+ gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x);
strong_xoffset = strong_x - entry->scroll_offset;
NULL, NULL,
event->button, event->time);
}
+
+static void
+gtk_entry_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time)
+{
+ GtkEntry *entry;
+
+ entry = GTK_ENTRY (widget);
+
+ entry->dnd_position = -1;
+ gtk_widget_queue_draw (widget);
+}
+
+static gboolean
+gtk_entry_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ GtkEntry *entry;
+ GtkWidget *source_widget;
+ GdkDragAction suggested_action;
+ gint new_position, old_position;
+ gint sel1, sel2;
+
+ entry = GTK_ENTRY (widget);
+
+ x -= widget->style->xthickness;
+ y -= widget->style->ythickness;
+
+ old_position = entry->dnd_position;
+ new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
+
+ source_widget = gtk_drag_get_source_widget (context);
+ suggested_action = context->suggested_action;
+
+ if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) ||
+ new_position < sel1 || new_position > sel2)
+ {
+ if (source_widget == widget)
+ {
+ /* Default to MOVE, unless the user has
+ * pressed ctrl or alt to affect available actions
+ */
+ if ((context->actions & GDK_ACTION_MOVE) != 0)
+ suggested_action = GDK_ACTION_MOVE;
+ }
+
+ entry->dnd_position = new_position;
+ }
+ else
+ {
+ if (source_widget == widget)
+ suggested_action = 0; /* Can't drop in selection where drag started */
+
+ entry->dnd_position = -1;
+ }
+
+ gdk_drag_status (context, suggested_action, time);
+
+ if (entry->dnd_position != old_position)
+ gtk_widget_queue_draw (widget);
+
+ return TRUE;
+}
+
+static void
+gtk_entry_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ GtkEntry *entry;
+ GtkEditable *editable;
+ gchar *str;
+
+ entry = GTK_ENTRY (widget);
+ editable = GTK_EDITABLE (widget);
+
+ str = gtk_selection_data_get_text (selection_data);
+
+ if (str)
+ {
+ gint new_position;
+ gint sel1, sel2;
+
+ new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
+
+ if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) ||
+ new_position < sel1 || new_position > sel2)
+ {
+ gtk_editable_insert_text (editable, str, -1, &new_position);
+ }
+ else
+ {
+ /* Replacing selection */
+ gtk_editable_delete_text (editable, sel1, sel2);
+ gtk_editable_insert_text (editable, str, -1, &sel1);
+ }
+
+ g_free (str);
+ }
+}
+
+static void
+gtk_entry_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ gint sel_start, sel_end;
+
+ GtkEditable *editable = GTK_EDITABLE (widget);
+
+ if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
+ {
+ gchar *str = gtk_editable_get_chars (editable, sel_start, sel_end);
+
+ gtk_selection_data_set_text (selection_data, str);
+
+ g_free (str);
+ }
+
+}
+
+static void
+gtk_entry_drag_data_delete (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ gint sel_start, sel_end;
+
+ GtkEditable *editable = GTK_EDITABLE (widget);
+
+ if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
+ gtk_editable_delete_text (editable, sel_start, sel_end);
+}
guint editable : 1;
guint visible : 1;
guint overwrite_mode : 1;
+ guint in_drag : 1; /* Dragging within the selection */
guint16 text_length; /* length in use, in chars */
guint16 text_max_length;
guint16 preedit_length; /* length of preedit string, in bytes */
guint16 preedit_cursor; /* offset of cursor within preedit string, in chars */
+
+ gint dnd_position; /* In chars, -1 == no DND cursor */
+
+ gint drag_start_x;
+ gint drag_start_y;
gunichar invisible_char;
};
*/
#define FOCUS_EDGE_WIDTH 1
-#define DRAG_THRESHOLD 8
#define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
#define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
text_view->drag_start_x >= 0)
{
gint x, y;
- gint dx, dy;
gdk_window_get_pointer (text_view->text_window->bin_window,
&x, &y, NULL);
- dx = text_view->drag_start_x - x;
- dy = text_view->drag_start_y - y;
-
- if (ABS (dx) > DRAG_THRESHOLD ||
- ABS (dy) > DRAG_THRESHOLD)
+ if (gtk_drag_check_threshold (widget,
+ text_view->drag_start_x,
+ text_view->drag_start_y,
+ x, y))
{
GtkTextIter iter;
gint buffer_x, buffer_y;